<template>
  <div :class="classes">
    <div :class="[prefixCls+ '-list']" ref="hours">
      <ul :class="[prefixCls + '-ul']">
        <li :class="getCellCls(item)"
            v-for="(item,index) in hoursList" :key="index"
            v-show="!item.hide"
            @click="handleClick('hours', item)">
          {{ formatTime(item.text) }}
        </li>
      </ul>
    </div>
    <div :class="[prefixCls+ '-list']" ref="minutes">
      <ul :class="[prefixCls + '-ul']">
        <li :class="getCellCls(item)"
            v-for="(item,index) in minutesList" :key="index"
            v-show="!item.hide"
            @click="handleClick('minutes', item)">{{ formatTime(item.text) }}
        </li>
      </ul>
    </div>
    <div :class="[prefixCls+ '-list']" v-show="showSeconds" ref="seconds">
      <ul :class="[prefixCls + '-ul']">
        <li :class="getCellCls(item)"
            v-for="(item,index) in secondsList" :key="index"
            v-show="!item.hide"
            @click="handleClick('seconds', item)">{{ formatTime(item.text) }}
        </li>
      </ul>
    </div>
  </div>
</template>
<script>
  import Options from '../util/time-mixins'
  import { deepCopy } from '../../../utils/util'
  import { scrollTop, firstUpperCase } from '../../../utils/dom'

  const prefixCls = 'bin-time-picker-cells'
  const timeParts = ['hours', 'minutes', 'seconds']

  export default {
    name: 'TimeSpinner',
    mixins: [Options],
    props: {
      hours: {
        type: [Number, String],
        default: NaN
      },
      minutes: {
        type: [Number, String],
        default: NaN
      },
      seconds: {
        type: [Number, String],
        default: NaN
      },
      showSeconds: {
        type: Boolean,
        default: true
      },
      steps: {
        type: Array,
        default: () => []
      }
    },
    data () {
      return {
        spinerSteps: [1, 1, 1].map((one, i) => Math.abs(this.steps[i]) || one),
        prefixCls: prefixCls,
        compiled: false,
        focusedColumn: -1, // which column inside the picker
        focusedTime: [0, 0, 0] // the values array into [hh, mm, ss]
      }
    },
    computed: {
      classes () {
        return [
          `${prefixCls}`,
          {
            [`${prefixCls}-with-seconds`]: this.showSeconds
          }
        ]
      },
      hoursList () {
        let hours = []
        const step = this.spinerSteps[0]
        const focusedHour = this.focusedColumn === 0 && this.focusedTime[0]
        const hourTmpl = {
          text: 0,
          selected: false,
          disabled: false,
          hide: false
        }

        for (let i = 0; i < 24; i += step) {
          const hour = deepCopy(hourTmpl)
          hour.text = i
          hour.focused = i === focusedHour

          if (this.disabledHours.length && this.disabledHours.indexOf(i) > -1) {
            hour.disabled = true
            if (this.hideDisabledOptions) hour.hide = true
          }
          if (this.hours === i) hour.selected = true
          hours.push(hour)
        }

        return hours
      },
      minutesList () {
        let minutes = []
        const step = this.spinerSteps[1]
        const focusedMinute = this.focusedColumn === 1 && this.focusedTime[1]
        const minuteTmpl = {
          text: 0,
          selected: false,
          disabled: false,
          hide: false
        }

        for (let i = 0; i < 60; i += step) {
          const minute = deepCopy(minuteTmpl)
          minute.text = i
          minute.focused = i === focusedMinute

          if (this.disabledMinutes.length && this.disabledMinutes.indexOf(i) > -1) {
            minute.disabled = true
            if (this.hideDisabledOptions) minute.hide = true
          }
          if (this.minutes === i) minute.selected = true
          minutes.push(minute)
        }
        return minutes
      },
      secondsList () {
        let seconds = []
        const step = this.spinerSteps[2]
        const focusedMinute = this.focusedColumn === 2 && this.focusedTime[2]
        const secondTmpl = {
          text: 0,
          selected: false,
          disabled: false,
          hide: false
        }

        for (let i = 0; i < 60; i += step) {
          const second = deepCopy(secondTmpl)
          second.text = i
          second.focused = i === focusedMinute

          if (this.disabledSeconds.length && this.disabledSeconds.indexOf(i) > -1) {
            second.disabled = true
            if (this.hideDisabledOptions) second.hide = true
          }
          if (this.seconds === i) second.selected = true
          seconds.push(second)
        }

        return seconds
      }
    },
    methods: {
      getCellCls (cell) {
        return [
          `${prefixCls}-cell`,
          {
            [`${prefixCls}-cell-selected`]: cell.selected,
            [`${prefixCls}-cell-focused`]: cell.focused,
            [`${prefixCls}-cell-disabled`]: cell.disabled

          }
        ]
      },
      chooseValue (values) {
        const changes = timeParts.reduce((obj, part, i) => {
          const value = values[i]
          if (this[part] === value) return obj
          return {
            ...obj,
            [part]: value
          }
        }, {})
        if (Object.keys(changes).length > 0) {
          this.emitChange(changes)
        }
      },
      handleClick (type, cell) {
        if (cell.disabled) return
        const data = { [type]: cell.text }
        this.emitChange(data)
      },
      emitChange (changes) {
        this.$emit('on-change', changes)
        this.$emit('on-pick-click')
      },
      scroll (type, index) {
        const from = this.$refs[type].scrollTop
        const to = 24 * this.getScrollIndex(type, index)
        scrollTop(this.$refs[type], from, to, 500)
      },
      getScrollIndex (type, index) {
        const Type = firstUpperCase(type)
        const disabled = this[`disabled${Type}`]
        if (disabled.length && this.hideDisabledOptions) {
          let _count = 0
          disabled.forEach(item => item <= index ? _count++ : '')
          index -= _count
        }
        return index
      },
      updateScroll () {
        this.$nextTick(() => {
          timeParts.forEach(type => {
            this.$refs[type].scrollTop = 24 * this[`${type}List`].findIndex(obj => obj.text === this[type])
          })
        })
      },
      formatTime (text) {
        return text < 10 ? '0' + text : text
      },
      updateFocusedTime (col, time) {
        this.focusedColumn = col
        this.focusedTime = time.slice()
      }
    },
    watch: {
      hours (val) {
        if (!this.compiled) return
        this.scroll('hours', this.hoursList.findIndex(obj => obj.text === val))
      },
      minutes (val) {
        if (!this.compiled) return
        this.scroll('minutes', this.minutesList.findIndex(obj => obj.text === val))
      },
      seconds (val) {
        if (!this.compiled) return
        this.scroll('seconds', this.secondsList.findIndex(obj => obj.text === val))
      },
      focusedTime (updated, old) {
        timeParts.forEach((part, i) => {
          if (updated[i] === old[i] || typeof updated[i] === 'undefined') return
          const valueIndex = this[`${part}List`].findIndex(obj => obj.text === updated[i])
          this.scroll(part, valueIndex)
        })
      }
    },
    mounted () {
      this.$nextTick(() => {
        this.compiled = true
      })
    }
  }
</script>
